import types
import Queue
import socket
import httplib
import xmlrpclib
import threading

from sorto_board import SortoBoard

class RemovePlayerException(Exception):
    def __init__(self, msg=""):
        Exception.__init__(self, msg)
        self._msg = msg
        return
    def __str__(self):
        return self._msg
    pass # End of class RemovePlayerException

class GameTurnData(object):
    def __init__(self, game_number, round, roll, playing_counters,
                 previous_board, previous_counter, player_colors,
                 last_games_seed):
        self.game_number      = game_number
        self.round            = round
        self.roll             = roll
        self.playing_counters = playing_counters
        self.previous_board   = previous_board
        self.previous_counter = previous_counter
        self.player_colors    = player_colors
        self.last_games_seed  = last_games_seed
        return
    pass # End of class GameTurnData

class SortoRemotePlayerThread(threading.Thread):

    def __init__(self, addr):
        threading.Thread.__init__(self)
        self._player = xmlrpclib.ServerProxy(addr)
        self._abort  = False
        self._connection_lost = False
        self.play_game_turn_queue    = Queue.Queue()
        self.game_turn_results_queue = Queue.Queue()
        return

    def __getattr__(self, item):
        return getattr(self._player, item)

    def play_game_turn(self, game_number, round, roll,
                       playing_counters, previous_board, previous_counter,
                       player_colors,
                       last_games_seed):
        if self._connection_lost:
            raise RemovePlayerException("connection lost")
        data = GameTurnData(game_number, round, roll, playing_counters,
                            previous_board, previous_counter, player_colors,
                            last_games_seed)
        self.play_game_turn_queue.put(data)
        return

    def get_turn_results(self):
        res = None
        while res is None and not self._abort:
            try:
                res = self.game_turn_results_queue.get(timeout=0.1)
            except Queue.Empty:
                res = None
                pass
            if self._connection_lost:
                raise RemovePlayerException("connection lost")
            pass
        return res

    def abort(self):
        try:
            self._player.abort()
        except socket.error, error:
            pass
        except httplib.CannotSendRequest, ex:
            pass
        self.quit()
        return

    def quit(self):
        self._abort = True
        return

    def run(self):

        while not self._abort:
            round_info = None
            while round_info is None and not self._abort:
                try:
                    round_info = self.play_game_turn_queue.get(timeout=0.1)
                except Queue.Empty:
                    round_info = None
                    pass
                pass
            if self._abort: 
                return
            try:
                self._player.play_game_turn(round_info.game_number,
                                            round_info.round,
                                            round_info.roll,
                                            round_info.playing_counters,
                                            round_info.previous_board,
                                            round_info.previous_counter,
                                            round_info.player_colors,
                                            round_info.last_games_seed)
                res = self._player.get_turn_results()
            except socket.error, error:
                if error[0] == 61: # Connection refused
                    self._connection_lost = True
                    return
                raise error
            #except Exception, ex:
            #    return
            if self._abort: 
                return
            (board, player_counters) = res
            if type(board) is types.DictType:
                # This is needed when using XMLRPC to translate from a
                # dictionary back into a SortoBoard
                board = SortoBoard(board)

            self.game_turn_results_queue.put((board, player_counters))
            pass
        return

    pass # End of class SortoRemotePlayerThread
